﻿namespace GoFun.Lib

open Positionen

[<AutoOpen>]
module BrettOperations =

    let brettDim (brett : Brett) = Array2D.length1 brett

    let createEmptyBoard (dim : int) : Brett = 
        Array2D.create dim dim PositionStatus.Empty

    let positionStatus (position : Position) (brett : Brett) =
        let (zeile, spalte) = position
        brett.[zeile, spalte]

    let setzePosition (status : PositionStatus) (brett : Brett) ((zeile, spalte) : Position)  =
        let dim = brettDim brett
        if validPos dim (zeile, spalte) |> not then brett else
        let brett = Array2D.copy brett
        brett.[zeile, spalte] <- status
        brett

    let setState (state : PositionStatus) ((row, col) : Position) (board : Brett) =
        let dim = brettDim board
        if validPos dim (row, col) |> not then board else
        let brett = Array2D.copy board
        brett.[row, col] <- state
        brett

    let setStates (state : PositionStatus) (board : Brett) (positions : Position seq) =
        positions |> Seq.fold (switch <| setState state) board

    let removeStone (pos : Position) (board : Brett) =
        board |> setState PositionStatus.Empty pos

    let setBlackStone (pos : Position) (board : Brett) =
        board |> setState PositionStatus.Black pos

    let setWhiteStone (pos : Position) (board : Brett) =
        board |> setState PositionStatus.White pos

    let setztePositonen (status : PositionStatus) (ps : Position seq) (brett : Brett) =
        ps |> Seq.fold (setzePosition status) brett

    let areConnected (a : Position) (b : Position) (brett : Brett) =
        let dim = brettDim brett
        let status p = brett |> positionStatus p
        let statusA = status a
        let gleicheFarbe pos = status pos = statusA
        let rec sucheWeg besucht lookAt =
            match lookAt with
            | [] -> false
            | p::_ when p = b -> true
            | p::ps when besucht |> Set.contains p -> sucheWeg besucht ps
            | p::ps ->
                let besucht = Set.add p besucht
                let relevantePos = surrounding dim p |> List.filter gleicheFarbe
                let lookAt = relevantePos@ps
                sucheWeg besucht lookAt
        sucheWeg Set.empty [a]
